import 'package:flutter/material.dart';
import 'dart:math';

class PathLineAnimation extends StatefulWidget {
  @override
  _PathLineAnimationState createState() => _PathLineAnimationState();
}

class _PathLineAnimationState extends State<PathLineAnimation>
    with SingleTickerProviderStateMixin {
  late Animation<double> animation;
  late AnimationController controller;

  void initState() {
    super.initState();
    controller =
        AnimationController(duration: const Duration(seconds: 2), vsync: this);
    animation = Tween<double>(begin: 0, end: 1.0).animate(CurvedAnimation(
      parent: controller,
      curve: Curves.easeInOutSine,
    ))
      ..addListener(() {
        setState(() {});
      });
    // ..addStatusListener((status) {
    //   if (status == AnimationStatus.completed) {
    //     controller.reverse();
    //   } else if (status == AnimationStatus.dismissed) {
    //     controller.forward();
    //   }
    // });
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
        child: CustomPaint(
          painter: PathLineAnimationPainter(
            animationValue: animation.value,
          ),
        ),
        onTap: () {
          controller.repeat();
          // if (controller.status == AnimationStatus.completed) {
          //   controller.reverse();
          // } else {
          //   controller.forward();
          // }
          // if (controller.isDismissed) {
          //   controller.forward();
          // }
        });
  }

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }
}

class PathLineAnimationPainter extends CustomPainter {
  final double animationValue;
  PathLineAnimationPainter({required this.animationValue});

  @override
  void paint(Canvas canvas, Size size) {
    //动画曲线：Curves.slowMiddle，控制器使用 repeat 模式
    //_drawLoadingCircle(canvas, size);
    //动画曲线：Curves.easeInOutQuart,控制器结束后使用 reverse 回到原位
    //_drawPendulum(canvas, size);
    //动画曲线：Curves.linear，控制器使用 repeat 模式
    _drawBezierCurve(canvas, size);
  }

  _drawBezierCurve(Canvas canvas, Size size) {
    var paint = Paint()
      ..style = PaintingStyle.stroke
      ..color = Colors.blue[400]!
      ..strokeWidth = 2.0;

    var controlHeight = 80.0;
    var center = Offset(size.width / 2, size.height / 2);
    final waveNum = 10;
    var path = Path();
    path.moveTo(0, size.height / 2);
    for (var i = 0; i < waveNum; ++i) {
      path.quadraticBezierTo(
          size.width / waveNum * i + size.width / waveNum / 2,
          size.height / 2 - controlHeight,
          size.width / waveNum * (i + 1),
          size.height / 2);
      canvas.drawPath(path, paint);
    }
    var leftPath = Path();
    leftPath.moveTo(0, size.height / 2);
    leftPath.quadraticBezierTo(size.width / 2, size.height / 2 - controlHeight,
        size.width, size.height / 2);
    //canvas.drawPath(path, paint);
    var metrics = path.computeMetrics();
    paint.color = Colors.red;
    paint.style = PaintingStyle.stroke;

    for (var pathMetric in metrics) {
      var tangent =
          pathMetric.getTangentForOffset(pathMetric.length * animationValue);

      var drawPath = Path();
      drawPath.moveTo(0, size.height / 2);
      drawPath.quadraticBezierTo(
          tangent!.position.dx / 2,
          tangent.position.dy - controlHeight * animationValue,
          tangent.position.dx,
          tangent.position.dy);
      var transform = Matrix4.identity()
        ..translate(center.dx, center.dy, 0.0)
        ..rotateY(pi * animationValue + 0.1)
        ..translate(-center.dx, -center.dy, 0.0);
      var transformedPath = drawPath.transform(transform.storage);
      canvas.drawPath(transformedPath, paint);
    }

    var rightPath = Path();

    rightPath.moveTo(size.width, size.height / 2);
    rightPath.quadraticBezierTo(
        size.width / 2, size.height / 2 + controlHeight, 0, size.height / 2);
    //canvas.drawPath(path, paint);
    var rightMetrics = rightPath.computeMetrics();
    paint.color = Colors.blue;
    //paint.style = PaintingStyle.fill;
    for (var pathMetric in rightMetrics) {
      var tangent =
          pathMetric.getTangentForOffset(pathMetric.length * animationValue);

      var drawPath = Path();
      drawPath.moveTo(size.width, size.height / 2);
      drawPath.quadraticBezierTo(
          (size.width + tangent!.position.dx) / 2,
          tangent.position.dy + controlHeight * animationValue,
          tangent.position.dx,
          tangent.position.dy);
      print(tangent.position.dx);
      var transform = Matrix4.identity()
        ..translate(center.dx, center.dy, 0.0)
        ..rotateY(pi / 4 * animationValue - 0.1)
        ..translate(-center.dx, -center.dy, 0.0);
      var transformedPath = drawPath.transform(transform.storage);
      canvas.drawPath(transformedPath, paint);
    }
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return true;
  }
}
